/**
 * 
 */
package ro.dandanciu.webgallery.services.impl;

import java.io.File;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.activation.MimetypesFileTypeMap;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Transactional;

import ro.dandanciu.webgallery.domainmodel.Gallery;
import ro.dandanciu.webgallery.domainmodel.Image;
import ro.dandanciu.webgallery.domainmodel.User;
import ro.dandanciu.webgallery.gallery.dto.GallerySyncDTO;
import ro.dandanciu.webgallery.services.GalleryServices;
import ro.dandanciu.webgallery.services.ImageServices;
import ro.dandanciu.webgallery.ui.filters.ImageSupplier;

/**
 * @author Dan
 *
 *
 */
@Transactional

public class GalleryServicesImpl implements GalleryServices {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger.getLogger(GalleryServicesImpl.class);

	private EntityManager em;
	
	@PersistenceContext
	public void setEntityManager(EntityManager em) {
		this.em = em;
	}
	
	private ImageServices imageServices;
	
	/**
	 * @param imageServices the imageServices to set
	 */
	public void setImageServices(ImageServices imageServices) {
		this.imageServices = imageServices;
	}

	/* (non-Javadoc)
	 * @see ro.dandanciu.webgallery.services.GalleryServices#getGalleriesByOwner(ro.dandanciu.webgallery.domainmodel.User)
	 */
	@SuppressWarnings("unchecked")
	public List<Gallery> getGalleriesByOwner(User owner, long galleryId, String filter) {
		if (filter == null) {
			filter = "";
		}
		filter += "%";
		
		List<Gallery> galleries = new ArrayList<Gallery>();
		if (galleryId < 0) {
			Query query = em.createNamedQuery("Gallery.findRootByOwner");
			query.setParameter("userId", owner.getUserId());
			query.setParameter("filter", filter);
			galleries = (List<Gallery>) query.getResultList();
		} else {
			Query query = em.createNamedQuery("Gallery.findByOwnerAndParent");
			query.setParameter("userId", owner.getUserId());
			query.setParameter("galleryId", galleryId);
			query.setParameter("filter", filter);
			galleries = (List<Gallery>) query.getResultList();
		}
		return galleries;
	}

	/* (non-Javadoc)
	 * @see ro.dandanciu.webgallery.services.GalleryServices#save(ro.dandanciu.webgallery.domainmodel.Gallery)
	 */
	
	public void save(Gallery gallery) {
		gallery.setUpdater(gallery.getOwner().getUserId());
		em.persist(gallery);
	}

	public Gallery getGalleryById(long galleryId) {
		return em.find(Gallery.class, galleryId);
	}

	@SuppressWarnings("unchecked")
	public List<Gallery> getPublicGalleries(String filter) {
		Query query = em.createNamedQuery("Gallery.findAllPublic");
		query.setParameter("filter", filter + "%");
		return (List<Gallery>) query.getResultList();
	}

	
	public void update(Gallery gallery) {
		gallery.setUpdater(gallery.getOwner().getUserId());
		em.merge(gallery);
	}
	
	@SuppressWarnings("unchecked")
	public Gallery getGalleryByOwnerAndName(String ownerUserId, String galleryName) {
		Query query = em.createNamedQuery("Gallery.findByOwnerAndName");
		query.setParameter("ownerUserId", ownerUserId);
		query.setParameter("galleryName", galleryName);
		List<Gallery> resultList = query.getResultList();
		Gallery gallery = null;
		if (resultList.size() > 0) {
			gallery = (Gallery) resultList.get(0);
		}
		return gallery;
	}
	
	public Set<GallerySyncDTO> preSynchronizeDifference(long galleryId) {
		if (logger.isDebugEnabled()) {
			logger.debug("synchronize(long) - start");
			logger.debug("galleryId:long = " + galleryId);
		}
		
		//get local images, the ones that are currently in the application
		Gallery gallery = getGalleryById(galleryId);
		List<Image> imagesLocal = imageServices.getImagesForGallery(gallery);
		
		//get remote images, the ones in the file system
		File directory  = new File(getFsPathForGallery(gallery));
		File[] filesRemote = new File[0];
		if (directory.exists() && directory.isDirectory()) {
			filesRemote = directory.listFiles();
		}
		Map<String, GallerySyncDTO> result = new HashMap<String, GallerySyncDTO>();
		for (Image image : imagesLocal) {
			GallerySyncDTO syncElement = new GallerySyncDTO(image.getName());
			syncElement.setStatus(GallerySyncDTO.Status.MISSING_ON_REMOTE);
			syncElement.setLocal(image);
			syncElement.setRemote(null);
			
			result.put(image.getName(), syncElement);
		}
		
		for (File file : filesRemote) {
			
			String name = file.getName();
			
			GallerySyncDTO syncElement;
			
			if (result.containsKey(name)) {
				syncElement = result.get(name);
				syncElement.setStatus(GallerySyncDTO.Status.SYNCRONIZED);
			} else {				
				syncElement = new GallerySyncDTO(name);
				syncElement.setStatus(GallerySyncDTO.Status.MISSING_ON_LOCAL);
				syncElement.setRemote(null);
			}

			Image image = new Image();
			image.setName(name);
			image.setSize(file.length());
			image.setContentType( new MimetypesFileTypeMap().getContentType(file));
			image.setUpdated(new Timestamp(file.lastModified()));
			syncElement.setRemote(image);
			result.put(image.getName(), syncElement);
		}

		if (logger.isDebugEnabled()) {
			logger.debug("synchronize(long) - end");
			logger.debug("return: " + result);
		}
		return new HashSet<GallerySyncDTO>(result.values());
	}

	private String getFsPathForGallery(Gallery gallery) {
		if (logger.isDebugEnabled()) {
			logger.debug("getFsPathForGallery(Gallery) - start"); //$NON-NLS-1$
			logger.debug("gallery: " + gallery); 
		}

		String path = "/";
		Gallery tempGallery = gallery;
		while (tempGallery != null) {
			path = "/" + tempGallery.getName().trim() + path;
			tempGallery = tempGallery.getParent();
		}
		

		String returnString = ImageSupplier.getImagesBase() + "/" + gallery.getOwner().getUserId() + path;
		if (logger.isDebugEnabled()) {
			logger.debug("getFsPathForGallery(Gallery) - end"); //$NON-NLS-1$
			logger.debug("return: " + returnString);
		}
		return returnString ;
	}

	
	public void syncronize(long galleryId, String[] deletes, String[] imports) {
		Gallery gallery = getGalleryById(galleryId);
				
		//get remote images, the ones in the file system
		File directory  = new File(getFsPathForGallery(gallery));
		
		for (String file : deletes) {
			deleteImage(galleryId, file);
		}
		
		for (String file : imports) {
			importImage(gallery, directory, file);
		}
		
	}

	private void importImage(Gallery gallery, File directory, String fileName) {
		File imageFile = new File(directory, fileName);
		String contentType = new MimetypesFileTypeMap().getContentType(imageFile);
		imageServices.add(imageFile, gallery, fileName, contentType);
	}

	private void deleteImage(long galleryId, String fileName) {
		imageServices.delete(galleryId, fileName);
	}	
}
